package sample.util;

import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.geometry.Orientation;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.SplitPane;
import javafx.scene.input.MouseButton;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Line;
import sample.SceneBuilder;

import java.io.File;
import java.net.MalformedURLException;
import java.util.concurrent.atomic.AtomicInteger;

/**

 * @name      :TicTacToe

 * @Description: the Scene of the TicTacToe game

*/
public class TicTacToe extends Scene {
    final private int [][] T3;
    // 1 for circle
    // -1 for cross
    // 2 for circle win
    // -2 for cross win
    private final AtomicInteger turn;
    private final DoubleProperty height;
    private final DoubleProperty width;
    // structure
    /*
    * sp|   s_1/s|s|s
    *   |   s_2/s|s|s
    *   |   s_3/s|s|s
    * */
    private final SplitPane split;

    public TicTacToe(Parent parent) throws MalformedURLException {
        this(parent,-1D,-1D);
    }
    public TicTacToe(Parent parent,double w,double h) throws MalformedURLException {
        super(parent,w,h);
        turn = new AtomicInteger(1);
        height = new SimpleDoubleProperty();
        width = new SimpleDoubleProperty();
        split = new SplitPane();
        this.setRoot(split);

        height.bind(split.heightProperty());
        width.bind(split.widthProperty());
        split.setOrientation(Orientation.VERTICAL);
        split.getItems().addAll(
                this.HorizonPane(3)
                ,this.HorizonPane(3)
                ,this.HorizonPane(3));

        T3= new int[][]{
                {0, 0, 0},
                {0, 0, 0},
                {0, 0, 0}
        };
        this.getStylesheets().add(new File("src/css/allSrc.css").toURI().toURL().toString());
//        this.getStylesheets().add(getClass().getResource("src/css/allSrc.css").toExternalForm());
        for(int i=0;i<9;++i){
            getSplitAction(i);
        }
    }
    public void getSplitAction(final int index){
        getSplit(index).setOnMouseClicked(e->{
            if(e.getButton()== MouseButton.MIDDLE){
                this.clear();
                return;
            }else if(e.getButton()== MouseButton.SECONDARY){
                // todo manage a series of ContextMenu to control the display of all
                // if click other place, this ContextMenu should hide
                ContextMenu context = new ContextMenu();
                context.getItems().addAll(Ctl.MenuWithText("VsAI"),Ctl.MenuWithText("clear"));
                context.show(this.split,e.getScreenX(),e.getScreenY());
                context.getItems().get(0).setOnAction(event-> {
                    this.VsAI();
                    context.hide();
                });
                context.getItems().get(1).setOnAction(event-> {
                    this.clear();
                    context.hide();
                });
                return;
            }
            boolean someWin=false;
            if(this.T3[index/3][index%3]==0){
                if(turn.get()==1){// Circle
                    turn.set(-1);
                    this.circle(getSplit(index));
                    this.T3[index/3][index%3]=1;
                    someWin=WinnerCheck(index)!=0;
                }else if(turn.get()==-1){// Cross
                    turn.set(1);
                    this.cross(getSplit(index));
                    this.T3[index/3][index%3]=-1;
                    someWin=WinnerCheck(index)!=0;
                }
//                for (int i = 0; i < 3; i++) {
//                    System.out.println(T3[i][0]+""+T3[i][1]+""+T3[i][2]);
//                }
//                System.out.println();
                if(draw()&&!someWin){
                    msg("no one");
                    this.clear();
                }
            }
        });
    }
    public boolean draw(){
        for (int i = 0; i < 9; i++) {
            if(T3[i/3][i%3]==0)
                return false;
        }return true;
    }
    public void clear(){
        for(int i = 0; i < 9; i++) {
//           getSplit(i).getItems().clear();
           getSplit(i).getStyleClass().clear();
           T3[i/3][i%3]=0;
        }
        turn.set(1);
    }
    public SplitPane getSplit(int index){
        if(index<0||index>8)return null;
        return (SplitPane)((SplitPane)this.split.getItems().get(index/3)).getItems().get(index%3);
    }
    private SplitPane HorizonPane(int index){
        return SceneBuilder.HorizonPane(index);
    }
    private void msg(){
        msg(winner());
    }
    private void msg(String m){
        new Alert("game over "+m+" wins",5).show();
    }
    public String winner(){
        return switch(turn.get()){
            case 2->"circle";
            case -2->"cross";
            default -> "";
        };
    }
    private int WinningBgSet(int r,int c,int pos){
        if(r==1||r==-1){
//            turn.set(r*2);
            // pos should be row
            pos/=3;
            getSplit(pos*3).getStyleClass().add("win");
            getSplit(pos*3+1).getStyleClass().add("win");
            getSplit(pos*3+2).getStyleClass().add("win");
        }else if(c==1||c==-1){
//            turn.set(c*2);
            // pos should be col
            pos%=3;
            getSplit(pos).getStyleClass().add("win");
            getSplit(pos+3).getStyleClass().add("win");
            getSplit(pos+6).getStyleClass().add("win");
        }else return 0;
        turn.set(r*2+c*2);
        msg();
        return turn.get();
    }
    // Set Winning set background
    private int WinningBgSet(int s,int b){
        if(s==1||s==-1){
//            turn.set(s*2);
            getSplit(2).getStyleClass().add("win");
            getSplit(4).getStyleClass().add("win");
            getSplit(6).getStyleClass().add("win");
        }else if(b==1||b==-1){
//            turn.set(b*2);
            getSplit(0).getStyleClass().add("win");
            getSplit(4).getStyleClass().add("win");
            getSplit(8).getStyleClass().add("win");
        }else return 0;
        turn.set(s*2+b*2);
        msg();
        return turn.get();
    }

    private void cross(double centerX, double centerY, double len){
//        Tic.cross(centerX,centerY,len,45,(Pane)this.getRoot());
    }
    private void cross(SplitPane sp){
        sp.getStyleClass().add("TCross");
//        sp.setBackground(new Image());
    }
    private void circle(double centerX,double centerY,double radius){
//        Circle circle=new Circle(radius);
    }
    private void circle(SplitPane sp){
        sp.getStyleClass().add("TCircle");
    }
    public static void cross(double centerX, double centerY, double len,double radio,SplitPane pane){
        double left = centerX - Math.sin(radio) * len / 2;
        double right = centerX + Math.sin(radio) * len / 2;
        double top = centerY - Math.cos(radio) * len / 2;
        double bottom = centerY + Math.cos(radio) * len / 2;
        Line slash=new Line(right,top,left,bottom);
//        slash.setStartX(right);
//        slash.setStartY(top);
//        slash.setEndX(left);
//        slash.setEndY(bottom);
        Line backSlash=new Line(left,top,right,bottom);
//        backSlash.setStartX(left);
//        backSlash.setStartY(top);
//        backSlash.setEndX(right);
//        backSlash.setEndY(bottom);
        pane.getItems().add(new Pane(slash,backSlash));
    }


    /**

     * @name      :WinnerCheck

     * @param     :[pos]

     * @return    :int

     * @Description: Winner check part

    */
    public int WinnerCheck(int pos){
        return switch(pos){
            case 1,3,5,7 -> //edge
                    edgeCheck(pos);
            case 0,2,4,6,8 -> vertexCheck(pos);
            default ->0;// It won't happen Seriously
        };
    }
    private int vertexCheck(int pos){
        int rel=edgeCheck(pos);
        if(rel==0){
            rel=WinningBgSet(slashCheck(),backSlashCheck());
        }return rel;
    }
    private int[] row(int index){
        int off=index*3;
        return new int[]{off,off+1,off+2};
    }
    private int[] col(int index){
        return new int[]{index,3+index,6+index};
    }
    private int edgeCheck(int pos){
        int r=rowCheck(pos/3);
        int c=colCheck(pos%3);
        WinningBgSet(r,c,pos);
        return r+c;
    }
    private int rowCheck(int row){
        return (T3[row][0]+T3[row][1]+T3[row][2])/3;
    }
    private int colCheck(int col){
        return (T3[0][col]+T3[1][col]+T3[2][col])/3;
    }
    private int slashCheck(){
        return (T3[2][0]+T3[1][1]+T3[0][2])/3;
    }
    private int backSlashCheck(){
        return (T3[0][0]+T3[1][1]+T3[2][2])/3;
    }

    // todo optimise
    // finish ContextMenu
    public void VsAI(){
        new Alert("Ai",5,SceneBuilder.NullScene()).show();
    }
}
